
#include "nane/InputSystem/InputAction.h"

#include <algorithm>

namespace nane 
{
    ////////////////////////////////////////////////////////////////////////////////////////////////
    InputAction::InputAction()
        : m_valueLast( 0.0f )
        , m_valueAverage( 0.0f )
        , m_isPressed( false )
        , m_wasPressed( 0 )
        , m_isReleased( true )
        , m_wasReleased( 0 )
    
    {
        
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    InputAction::~InputAction()
    {
        
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    void InputAction::AddInputBinding( const InputBinding& _inputBinding, uint32 _modifiersCount, const InputBindingModifier* _modifiers )
    {
        std::vector<InputBindingImpl>::iterator it_find =
                std::find(m_bindings.begin(), m_bindings.end(), _inputBinding);
        if( it_find == m_bindings.end() )
        {
            m_bindings.push_back(InputBindingImpl(_inputBinding, _modifiersCount, _modifiers));
        }
        else
        {
            (*it_find) = InputBindingImpl(_inputBinding, _modifiersCount, _modifiers);
        }
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    void InputAction::RemoveInputBinding( const InputBinding& _inputBinding )
    {
        m_bindings.erase(std::find(m_bindings.begin(), m_bindings.end(), _inputBinding));
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    void InputAction::PreUpdate()
    {
        for( std::vector<InputBindingImpl>::iterator it = m_bindings.begin(), it_end = m_bindings.end();
            it != it_end;
            ++it )
        {
            (*it).OnFrameBegin();
        }
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    void InputAction::Update( EInputDevice _inputDevice, InputEvent* _event )
    {
        for( std::vector<InputBindingImpl>::iterator it = m_bindings.begin(), it_end = m_bindings.end();
            it != it_end;
            ++it )
        {
            (*it).OnInputEvent(_inputDevice, _event);
        }
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    void InputAction::PostUpdate()
    {
        m_valueLast = 0.0f;
        m_valueAverage = 0.0f;
        m_isPressed = false;
        m_wasPressed = 0;
        m_isReleased = true;
        m_wasReleased = 0;

        
        float valueLastMaxNeg = 0.0f;
        float valueLastMaxPos = 0.0f;
        float valueAverageMaxNeg = 0.0f;
        float valueAverageMaxPos = 0.0f;
        for( std::vector<InputBindingImpl>::iterator it = m_bindings.begin(), it_end = m_bindings.end();
            it != it_end;
            ++it )
        {
            InputBindingImpl& binding = (*it);
            float valueLast = binding.GetLastValue();
            if( valueLast < 0.0f )
            {
                valueLastMaxNeg = std::min(valueLastMaxNeg, valueLast);
            }
            else
            {
                valueLastMaxPos = std::max(valueLastMaxPos, valueLast);
            }
            
            float valueAverage = binding.GetAverageValue();
            if( valueAverage < 0.0f )
            {
                valueAverageMaxNeg = std::min(valueAverageMaxNeg, valueAverage);
            }
            else
            {
                valueAverageMaxPos = std::max(valueAverageMaxPos, valueAverage);
            }
            
            m_wasPressed = std::max(m_wasPressed, binding.WasPressed());
            m_isPressed = m_isPressed || binding.IsPressed();
            m_wasReleased = std::max(m_wasReleased, binding.WasReleased());
            m_isReleased = m_isReleased && binding.IsReleased();
        }
        m_valueLast = valueLastMaxNeg + valueLastMaxPos;
        m_valueAverage = valueAverageMaxNeg + valueAverageMaxPos;
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    float InputAction::GetValueLast()
    {
        return m_valueLast;
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    float InputAction::GetValueAverage()
    {
        return m_valueAverage;
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    bool InputAction::IsPressed()
    {
        return m_isPressed;
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    uint32 InputAction::WasPressed()
    {
        return m_wasPressed;
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    bool InputAction::IsReleased()
    {
        return m_isReleased;
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    uint32 InputAction::WasReleased()
    {
        return m_wasReleased;
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
}   // namespace nane
